class_name BulletIntelligence
extends Node2D


var sender: Node2D
var attack: float = 0
var critical_rate: float = 0
var critical_bonus: float = 0
var knockback: float = 0
var hit_cam_shake_intensity: float = 0
var hit_cam_shake_duration: float = 0

var shoot_dir: Vector2 = Vector2.ZERO
@export var speed: float = 500
var velocity: Vector2 = Vector2.ZERO
@export var max_shoot_time: float = 3
var max_shoot_timer: float = 0

@onready var navigation_agent_2d: NavigationAgent2D = $NavigationAgent2D

@onready var search_area: Area2D = $SearchArea
@onready var hit_area: Area2D = $HitArea
var hit_targets: Array = []

var attack_target: Node2D = null


func _ready() -> void:
	max_shoot_timer = max_shoot_time
	

func process_hit():
	var areas = hit_area.get_overlapping_areas()
	if areas.size() <= 0: return
	
	for area in areas:
		var source = area.source
		if not source in hit_targets:
			hit_targets.append(source)
		
			var hit_data = get_hit_data()
			source.take_hit(hit_data, sender)
	
	queue_free()
	var level = get_tree().current_scene as Level
	level.emit_particle("particle_bullet_intelligence_hit_effect", global_position)
	level.camera.start_shake(hit_cam_shake_intensity, hit_cam_shake_duration)
	

func get_hit_data():
	var is_critical = randf() <= critical_rate
	var critical_attack = attack * (1.0 + critical_bonus)
	
	var hit_data = HitData.new()
	hit_data.is_critical = is_critical
	hit_data.attack = critical_attack if is_critical else attack
	hit_data.knockback = knockback
	
	return hit_data
	

func _physics_process(delta: float) -> void:
	process_search()
	process_hit()
	process_nav_move(delta)
	process_direct_move(delta)
	process_max_life_time(delta)
	process_rotation()
	

func process_rotation():
	if not velocity: return
	
	rotation = velocity.normalized().angle()
	

func process_max_life_time(delta: float):
	max_shoot_timer -= delta
	if max_shoot_timer <= 0:
		queue_free()


func _on_hit_area_body_entered(body: Node2D) -> void:
	queue_free()
	var level = get_tree().current_scene as Level
	level.emit_particle("particle_bullet_intelligence_hit_effect", global_position)
	level.camera.start_shake(hit_cam_shake_intensity, hit_cam_shake_duration)
	

func process_search():
	if attack_target: return
	
	var target_areas = search_area.get_overlapping_areas()
	if target_areas.size() <= 0: return
	
	var min_distance: float = INF
	var min_distance_target: Node2D = null
	for area in target_areas:
		var distance = global_position.distance_to(area.source.global_position)
		if distance < min_distance:
			min_distance = distance
			min_distance_target = area.source
	
	if min_distance_target:
		attack_target = min_distance_target
	

func process_direct_move(delta: float):
	if attack_target: return
	
	position += velocity * delta
	

func process_nav_move(delta: float):
	if not attack_target: return
	
	navigation_agent_2d.target_position = attack_target.global_position
		
	if navigation_agent_2d.is_navigation_finished(): return
	
	var next_pos = navigation_agent_2d.get_next_path_position()
	var dir = (next_pos - global_position).normalized()
	var target_velocity = dir * speed
	if navigation_agent_2d.avoidance_enabled:
		navigation_agent_2d.set_velocity(target_velocity)
	else:
		_on_navigation_agent_2d_velocity_computed(target_velocity, delta)
		
	
func _on_navigation_agent_2d_velocity_computed(safe_velocity: Vector2, delta: float = 0.0) -> void:
	velocity = velocity.lerp(safe_velocity, 0.05)
	position += velocity * delta
	
